# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: api\handlers\frontend\intents.py
import logging
from sqlalchemy import func as sql_func
from sqlalchemy import select as sql_select
from api.classes.frontend.auto import *
from api.handlers.frontend import FrontendResourceHandler
from db import Connection
from db.tables.intents import IntentRow, IntentsTable
from helpers.intents import intent_handlers
from helpers.rate_limiter import RateLimiter
from server.http_responses.http_errors import Http404, HttpError, TooManyRequests
from server.http_responses.http_status_codes import *
from settings_provider import settings

logger = logging.getLogger("api.Intents")


class Intents(FrontendResourceHandler):
    def get_intent(self, intent_id, **_):
        """
        This is request is not authenticated
        :param intent_id:
        :param _:
        :return: ClsIntentDescriptor
        """
        rt_intent_brute_force = settings.get("rt_intent_brute_force")
        if rt_intent_brute_force:
            r = rt_intent_brute_force.wait_time(self.remote_address)
            if r > 0:
                raise TooManyRequests(r)
        fq = sql_select(
            (
                IntentRow.data,
                IntentRow.status,
                (sql_func.current_timestamp() > IntentRow.expires).label("expired"),
            )
        ).where(IntentRow.intent_id == intent_id)
        dq = IntentsTable.delete().where(IntentRow.intent_id == intent_id)
        with Connection("master") as (db):
            result = db.execute(fq).fetchone()
            if not result:
                if rt_intent_brute_force:
                    rt_intent_brute_force.add(self.remote_address)
                return Http404()
            if result.expired:
                db.execute(dq)
                return Http404()
            if result.status == 0:
                status = "pending"
            else:
                status = "in-work"
            return ClsIntentDescriptor(action=result.data["action"], status=status)

    def confirm_intent(self, intent_id, body, **_):
        """
        This is request is not authenticated,
        Intents are not bound to specific shards, are only stored on the master shard
        :param intent_id:
        :param _:
        :param body: ClsIntentExtraData
        :return:
        """
        logger.debug("Processing intent %s", intent_id)
        rt_intent_brute_force = settings.get("rt_intent_brute_force")
        if rt_intent_brute_force:
            r = rt_intent_brute_force.wait_time(self.remote_address)
            if r > 0:
                raise TooManyRequests(r)
        extra_data = ClsIntentExtraData(**body)
        lq = (
            (IntentsTable.update(values=dict(status=1)))
            .where(IntentRow.intent_id == intent_id)
            .where(IntentRow.status == 0)
        )
        fq = sql_select(
            (
                IntentRow.data,
                IntentRow.status,
                (sql_func.current_timestamp() > IntentRow.expires).label("expired"),
            )
        ).where(IntentRow.intent_id == intent_id)
        dq = IntentsTable.delete().where(IntentRow.intent_id == intent_id)
        with Connection("master") as (db):
            result = db.execute(lq)
            if result.rowcount == 0:
                if rt_intent_brute_force:
                    rt_intent_brute_force.add(self.remote_address)
                logger.warning("Intent %s not found", intent_id)
                raise Http404()
            intent = db.execute(fq).fetchone()
            if not intent:
                logger.warning("Intent %s lost during operation", intent_id)
                raise Http404()
            if intent.expired:
                db.execute(dq)
                logger.warning("Intent %s expired", intent_id)
                raise Http404()
            intent = dict(intent)
        try:
            logging.debug("handling intent %s", intent_id)
            result = intent_handlers[intent["data"]["action"]](
                intent["data"], extra_data, remote_address=self.remote_address
            )
        except HttpError:
            logger.exception("intent_handlers failed with HttpError")
            with Connection("master") as (db):
                ulq = (
                    (IntentsTable.update(values=dict(status=0)))
                    .where(IntentRow.intent_id == intent_id)
                    .where(IntentRow.status == 1)
                )
                db.execute(ulq)
            raise
        except Exception as e:
            logger.exception(
                "intent_handlers %s:%s failed with %s", intent_id, intent["data"], e
            )
            with Connection("master") as (db):
                db.execute(dq)
        else:
            with Connection("master") as (db):
                db.execute(dq)

        if not result:
            return Http204()
        else:
            return result
